#include "rectangleH.h"
#include "PointH.h"
#include <conio.h>
#include <iostream>

using namespace std;


void gotoxy(int, int);
void clrscr();


Rectangl& Rectangl::operator=(const Rectangl &copyObj){ //there's a dry copy anyway when you're doing rectangle = rectangle so why we need this ? anyway I'm moving dirX,dirY from here to shape 

	//Checks self copy - if yes nothing to do
	if (this == &copyObj) return *this;
	//copy
	m_sizeX = copyObj.m_sizeX, m_sizeY = copyObj.m_sizeY;
	m_symb = copyObj.m_symb;
	m_dirX = copyObj.m_dirX, m_dirY = copyObj.m_dirY, m_tempDirX = m_tempDirX, m_tempDirY = copyObj.m_dirY;
	m_prevDirX = copyObj.m_prevDirX, m_prevDirY = copyObj.m_prevDirY;
	exit_dir = exit_dir;
	m_TL = copyObj.m_TL, m_TR = copyObj.m_TR, m_BL = copyObj.m_BL, m_BR = copyObj.m_BR;
	bumped = copyObj.bumped;
	//return existing object 
	return *this;

}
void Rectangl::init() //init the Rectangle object
{
		//If Adding Data members, Please remember to update the operator assignment "="
	    m_sizeX = 0;
	    m_sizeY = 0;
        exit_dir = -1;
		m_dirX = m_dirY = m_tempDirX = m_tempDirY = 0;
        m_prevDirX = m_prevDirY = 0;
		//system("cls");
		setPos(0,0);
		setSize(0,0);
		setSymbol('*');
		calcRectanglePoint();
		bool bumped = false;
}

bool Rectangl::isEqual(Rectangl * rec){
	if (rec->m_TL.isEqual(m_TL) && rec->m_sizeX == m_sizeX && rec->m_sizeY == m_sizeY) return true;
	return false;
}


void Rectangl::setPos(int x, int y) //Set coordinations
{
   m_TL.setPos(x,y);
   calcRectanglePoint();
}

void Rectangl::resetPos(int x, int y){ //reset the coord.
	
	if(m_sizeX > 0 && m_sizeY > 0){
		m_TL.setPos(x,y);
	}
	else
	{
		cout << "ERROR: Rectangle size is 0, use setPos() to initialize the rectangle."<< endl;
	}
	
}


void Rectangl::getPos(int &x, int &y) //Pulls out the index of x and y parameters and assign
{
	m_TL.getPos(x,y);
}


void Rectangl::getSize(int &x, int &y) //Pulls out the index of x and y parameters and assign
{
	x = m_sizeX;
	y = m_sizeY;
}


void Rectangl::setSize(int x, int y) //Set size of X and Y intervals (should be valid input)
{
	m_sizeX = x;
	m_sizeY = y;
}

void Rectangl::drawPoint(char c) //draw point
{
	m_TL.draw(c);
}


void Rectangl::draw(int drawingOption, Screen * s) // prior to drawing func
{
	int m_TLointX, m_TLointY;
	getPos(m_TLointX,m_TLointY);

	if (!m_sizeX || !m_sizeY)
	{
		cout << "ERROR: Go back to class - Rectangl::setSize() is not initialized,\nPlease Initialize! [i.e. Rectangl::setSize()]\n" << endl;
	}

	if(m_TLointX+m_sizeX<0 || m_TLointX>MAX_SCR_WID-1) return;
	if(m_TLointY+m_sizeY<0 || m_TLointY>MAX_SCR_LEN-1) return;

	drawRectangle(drawingOption,s);

}


void Rectangl::drawRectangle(int option, Screen * s) //drawing func based on checking each point if it's exist in Screen 80x25
{
	int pointX, pointY;
	
	getPos(pointX,pointY);

	
	for(int i=pointX; i < m_sizeX+pointX; i++) // printing the  vertical x row up and down
	{
		if(isInScreen(i,pointY)){
			if(!s) // if pointer to Screen is NULL do cout
			{gotoxy(i,pointY); cout << m_symb;}
			else s->setToScreenBuffer(pointY,i); // else meaning that an address of Screen object has been sent, thus print to Screen Buffer
		}
		if(isInScreen(i,pointY+m_sizeY-1)){
			if(!s){ // if pointer to Screen is NULL do cout
			gotoxy(i,(pointY+m_sizeY-1)); cout << m_symb;}
			 else s->setToScreenBuffer((pointY+m_sizeY-1),i); // else meaning that an address of Screen object has been sent, thus print to Screen Buffer
		}
	}

	
	for(int i=pointY; i < m_sizeY+pointY; i++) // printing the y row left and right
	{
		if(isInScreen(pointX,i)){ 
			if(!s){ // if pointer to Screen is NULL do cout
				gotoxy(pointX,i); cout << m_symb;}
			else s->setToScreenBuffer(i,pointX); // else meaning that an address of Screen object has been sent, thus print to Screen Buffer
		}
		    if(option == 0 && i < m_sizeY+pointY-2)
			{
				for(int j=pointX+1; j <  m_sizeX+pointX-1; j++)
					{if(isInScreen(j,i)){
						if(!s){ // if pointer to Screen is NULL do cout
						gotoxy(j,i+1); cout << " ";}
						else s->setToScreenBuffer(i+1,j,' '); // else meaning that an address of Screen object has been sent, thus print to Screen Buffer
				}
				}
			}
	
		if(isInScreen(pointX+m_sizeX-1,i)){
			if(!s)
				{gotoxy(pointX+m_sizeX-1,i); cout << m_symb;}	
			else s->setToScreenBuffer(i,pointX+m_sizeX-1);
		}
	}

	gotoxy(0,0);
}


bool Rectangl::isInScreen(int x, int y) // is coord. in screen ?
{
	if( x >=0 && x <= MAX_SCR_WID-1)
		if (y >= 0 && y <= MAX_SCR_LEN-1)
			return true;
		
	return false;
}

bool Rectangl::isInScreen(Point p) // is coord. in screen ?
{
	int x,y;
	this->getPos(x,y);

	if (x < MAX_SCR_WID-1 && y < MAX_SCR_LEN && x>0 && y>0) 
		return true;
	return false;
}

bool Rectangl::isInScreen(Rectangl * r)
{
	Point p1,p2,p3,p4;

	p1 = this->getPointTL();
	p2 = this->getPointTR();
	p3 = this->getPointBL();
	p4 = this->getPointBR();

	if (this->isInScreen(p1) && this->isInScreen(p2) && this->isInScreen(p3) && this->isInScreen(p4))
		return true;
	return false;
}

bool Rectangl::isPointIn(int x, int y)
{
	int m_TLpointX, m_TLpointY;
	m_TL.getPos(m_TLpointX,m_TLpointY);
	
	if( x >= m_TLpointX && x < (m_TLpointX + m_sizeX))
	
	{
		if( y >= m_TLpointY && y < (m_TLpointY + m_sizeY))
		
			return true;
	}

	return false;
}

bool Rectangl::pointEntirelyInRectangle(int x, int y)
{
	int m_TLpointX, m_TLpointY;
	m_TL.getPos(m_TLpointX,m_TLpointY);
	
	if( x >= m_TLpointX && x < (m_TLpointX + m_sizeX))
	
	{
		if( y >= m_TLpointY && y < (m_TLpointY + m_sizeY))
		
			return true;
	}

	return false;
}

void Rectangl::getDir(int &x, int &y)
{
	x = m_dirX;
	y = m_dirY;
}


Point Rectangl::getPointTL()
{
	return m_TL;
}
Point Rectangl::getPointTR()
{
	return m_TR;
}
Point Rectangl::getPointBL()
{
	return m_BL;
}
Point Rectangl::getPointBR()
{
	return m_BR;
}

void Rectangl::calcRectanglePoint(){
	
	int x,y;
	m_TL.getPos(x,y);
	m_TR.setPos(x+m_sizeX-1,y);
	m_BL.setPos(x,y+m_sizeY-1);
	m_BR.setPos(x+m_sizeX-1,y+m_sizeY-1);
}


void Rectangl::printRectangleToScreenBuffer(int displayChoice, Screen * s)
{
	draw(displayChoice,s);
}



bool Rectangl::isOverlap(Rectangl *RectB){

	int recA_X1, recA_X2;
	int recA_Y1, recA_Y2;
	int recB_X1, recB_X2;
	int recB_Y1, recB_Y2;

	getPos(recA_X1,recA_Y1);
	recA_X2 = recA_X1 + this->m_sizeX;
	recA_Y2 = recA_Y1 + this->m_sizeY;

	RectB->getPos(recB_X1,recB_Y1);
	recB_X2 = recB_X1 + RectB->m_sizeX;
	recB_Y2 = recB_Y1 + RectB->m_sizeY;
	
	if (recA_X1 < recB_X2 && recA_X2 > recB_X1 && recA_Y1 < recB_Y2 && recA_Y2 > recB_Y1)
		return true;
	return false;
}
//Checks if this* rectangle is containing another rectangle within it (rec)
//if yes returns true if not returns false - false means that the other rectangle is not within this rectangle (could be the other way)
bool Rectangl::isContaining(Rectangl * rec)
{
	Point TL,BR;
	int x1,y1,x2,y2,
		X1,Y1,X2,Y2;
	TL = rec->getPointTL();
	BR = rec->getPointBR();

	TL.getPos(x1,y1);
	BR.getPos(x2,y2);


	TL = this->getPointTL();
	BR = this->getPointBR();

	TL.getPos(X1,Y1);
	
	BR.getPos(X2,Y2);

	if (x1 >= X1 && x2 <= X2 && y1 >= Y1 && y2 <= Y2) 
		return true;

	return false;

}


bool Rectangl::isRectangleTouchesRectangle(Rectangl * rec)
{
	int x,y;
	int sizeX,sizeY;

	rec->getPos(x,y);
	rec->getSize(sizeX,sizeY);

	for(int i=x; i < x+sizeX; i++)
		{if(isPointTouchesRectangle(i,y))
		return true;}

	for(int i=x; i < x+sizeX; i++)
		{if(isPointTouchesRectangle(i,y+sizeY))
		return true;}

	for(int i=y; i < y+sizeY; i++)
		{if(isPointTouchesRectangle(x,i))
		return true;}

	for(int i=y; i < y+sizeY; i++)
		{if(isPointTouchesRectangle(x+sizeX,i))
		return true;}

	return false;
}



bool Rectangl::isPointTouchesRectangle(int x, int y)
{
	int m_x, m_y;

	getPos(m_x,m_y);

	for(int i=m_x; i < m_x + m_sizeX; i++)
	{  if( x == i)
			if((m_y == y) || (m_y+m_sizeY == y))
				return true;
	}

	for(int i=m_y; i < m_y + m_sizeY; i++)
	{  if( y == i)
			if((m_x == x) || (m_x+m_sizeX == x))
				return true;
	}

	return false;
}


bool Rectangl::isEntirelyContained(Rectangl * rec){
	//pointInRectangle

	
	int x2,y2,sizeX_2,sizeY_2;
	rec->m_TL.getPos(x2,y2);
	
	sizeX_2 = rec->m_sizeX;
	sizeY_2 = rec->m_sizeY;

	if (pointEntirelyInRectangle(x2,y2) 
		&& pointEntirelyInRectangle(x2+sizeX_2,y2)
		&& pointEntirelyInRectangle(x2,y2+sizeY_2) 
		&& pointEntirelyInRectangle(x2+sizeX_2,y2+sizeY_2)) 
		return true;


	
	return false;
	
}

bool Rectangl::isTangentFromOutside(Rectangl * RectB){


	int recA_X1, recA_X2;
	int recA_Y1, recA_Y2;
	int recB_X1, recB_X2;
	int recB_Y1, recB_Y2;

	getPos(recA_X1,recA_Y1);
	recA_X1--;
	recA_Y1--;
	recA_X2 = recA_X1 + this->m_sizeX+2;
	recA_Y2 = recA_Y1 + this->m_sizeY+2;

	RectB->getPos(recB_X1,recB_Y1);
	recB_X2 = recB_X1 + RectB->m_sizeX;
	recB_Y2 = recB_Y1 + RectB->m_sizeY;
	
	if (recA_X1 < recB_X2 && recA_X2 > recB_X1 && recA_Y1 < recB_Y2 && recA_Y2 > recB_Y1)
		return true;
	return false;
	
}



bool Rectangl::isTangentFromInside(Rectangl * RectB){



	int recA_X1, recA_X2;
	int recA_Y1, recA_Y2;
	int recB_X1, recB_X2;
	int recB_Y1, recB_Y2;

	getPos(recA_X1,recA_Y1);
	
	recA_X2 = recA_X1 + this->m_sizeX+2;
	recA_Y2 = recA_Y1 + this->m_sizeY+2;

	RectB->getPos(recB_X1,recB_Y1);
	recB_X1--;
	recB_Y1--;
	recB_X2 = recB_X1 + RectB->m_sizeX+2;
	recB_Y2 = recB_Y1 + RectB->m_sizeY+2;
	
	if (recA_X1 < recB_X2 && recA_X2 > recB_X1 && recA_Y1 < recB_Y2 && recA_Y2 > recB_Y1)
		return true;
	return false;
	
}



void Rectangl::getPosPointByDirection(int &r_posX, int &r_posY, int r_dir_x, int r_dir_y, Rectangl * r) // Which Main Position (TL/TR/BL/BR) am I pointing at ?
{
	
	int r_sizeX, r_sizeY, r_TLposX, r_TLposY;

	r->getPos(r_TLposX,r_TLposY);
	r->getSize(r_sizeX,r_sizeY);

	if(r_dir_x>=0){
		if(r_dir_y>=0) // BR
		{
			r_posX = r_TLposX + r_sizeX-1;
			r_posY = r_TLposY + r_sizeY-1;
		}
		else{  // TL
			r_posX = r_TLposX + r_sizeX-1;
			r_posY = r_TLposY;
		}
	}

    else{
		if(r_dir_y>0) // BL 
		{
				r_posX = r_TLposX;
				r_posY = r_TLposY + r_sizeY-1;
		}
		else{ // TR
			r_posX = r_TLposX;
			r_posY = r_TLposY;
		}
				
	}
}


bool Rectangl::isDirectionsResetBorders() // Checks clashes with screen borders
{
	int r_posX, r_posY;
	bool chengeMade = false;
	int dirX, dirY;

	this->getIntegerDirectionExplicitly(dirX,dirY);

    getPosPointByDirection(r_posX,r_posY,dirX,dirY,this);

	if(r_posX+dirX > MAX_SCR_WID || r_posX+dirX < MIN_SCR_WIDTH-1) { 

		this->resetDirectionX();
		dirX = -dirX; 
		chengeMade = true;
	}

	if(r_posY+dirY > MAX_SCR_LEN || r_posY+dirY < MIN_SCR_LEN-1) { 
		
		this->resetDirectionY();
		dirY = -dirY;
		chengeMade = true;
	}

    if(chengeMade) return true;

	return false;
	  
}




#define MAX_SCR_WID 80
#define MAX_SCR_LEN 25